use dashmap::DashMap;
use log::{error};
use std::fs;
use std::path::{Path, PathBuf};
use std::sync::OnceLock;
use std::time::{SystemTime, UNIX_EPOCH};
use walkdir::WalkDir;

/// markdown与之对应的html存储
pub struct MarkdownHtml {
    pub markdown_path: PathBuf,
    pub html_path: PathBuf,
    pub cache_generated_time: u64,
    pub hash_code: String,
}

/// 定义全局 DashMap —— 线程安全、懒初始化、高并发
static GLOBAL_DASHMAP: OnceLock<DashMap<String, MarkdownHtml>> = OnceLock::new();

/// 获取全局 DashMap 的引用（初始化一次，后续直接返回）
fn global_map() -> &'static DashMap<String, MarkdownHtml> {
    GLOBAL_DASHMAP.get_or_init(DashMap::new)
}

/// 添加对md的支持
fn markdown_to_html(markdown_input: &str) -> String {
    let parser = pulldown_cmark::Parser::new(markdown_input);
    let mut html_output = String::new();
    pulldown_cmark::html::push_html(&mut html_output, parser);
    html_output
}

/// 缓存路径
const CACHE_DIR: &str = "./.cache";

/// 创建md->html的文件夹
/// 不能每次都转换，如果发现转换的文件夹中还存在对应名称的html，优先使用对应
/// 文件夹中的html，除非重启服务，这样会自动删除对应文件夹中的转换html，即临时文件
pub fn scan_markdown() {
    let map = global_map();
    // 清理旧缓存
    if PathBuf::from(CACHE_DIR).exists() {
        if let Err(e) = fs::remove_dir_all(CACHE_DIR) {
            error!(
                "[退出markdown文件扫描] 无法删除{}，请排查问题后重启应用！详细错误如下：{}",
                CACHE_DIR,
                e.to_string()
            );
            return;
        }
    }

    // 清空缓存
    map.clear();

    // 重建缓存目录
    fs::create_dir_all(CACHE_DIR).expect("无法创建缓存目录，请排查问题后重启应用！");
    if let Err(e) = fs::create_dir_all(CACHE_DIR) {
        error!(
            "[退出markdown文件扫描] 无法创建缓存目录：{}，请排查问题后重启应用！详细错误如下：{}",
            CACHE_DIR,
            e.to_string()
        );
        return;
    }

    // 扫描、转换、添加
    let file_vec = WalkDir::new("static").into_iter();
    for entry in file_vec {
        let entry = match entry {
            Ok(e) => e,
            Err(e) => {
                error!("[跳过文件] 扫描markdown文件出错：{}", e.to_string());
                continue;
            }
        };
        let path = entry.path();
        let markdown_path = entry.path().to_path_buf();
        if path.is_file() && path.extension().map_or(false, |ext| ext == "md") {
            let path_str = match path.to_str() {
                Some(s) => s,
                None => {
                    error!("[跳过文件] 非UTF-8文件名: {:?}", path);
                    continue;
                }
            };

            // 读取文件内容
            let mut content = match fs::read_to_string(path) {
                Ok(content) => content,
                Err(e) => {
                    error!("[跳过文件] 读取{}内容失败，详细错误信息：{}", path.display(), e.to_string());
                    continue;
                }
            };
            // 计算内容hash
            let content_hash = blake3::hash(content.as_bytes());
            // 如果
            // md 转 html
            if !content.is_empty() {
                content = markdown_to_html(&content);
            }

            // 转换并写入文件
            let millis = match SystemTime::now().duration_since(UNIX_EPOCH) {
                Ok(n) => n.as_millis(),
                Err(e) => {
                    error!(
                        "[跳过文件] 系统时间不能早于Unix纪元，详细错误如下：{}",
                        e.to_string()
                    );
                    continue;
                }
            };

            let hash_str = content_hash.to_hex().to_string();
            let new_file_path = Path::new(CACHE_DIR).join(format!("{}.html", hash_str));
            if let Err(e) = fs::write(&new_file_path, content) {
                error!(
                    "[跳过文件] 创建缓存文件失败：{}，详细错误如下：{}",
                    new_file_path.display(),
                    e.to_string()
                );
                continue;
            }

            // 添加文件信息到缓存中
            let entity = MarkdownHtml {
                markdown_path,
                html_path: new_file_path,
                cache_generated_time: millis as u64,
                hash_code: content_hash.to_string(),
            };
            map.insert(path_str.to_string(), entity);
        }
    }
    // print_cached();
}

/// 根据 markdown 路径，获取预渲染好的 HTML 内容（从缓存文件读取）
pub fn get_cached_html(md_path: &str) -> Option<MarkdownHtml> {
    let map = global_map();
    let entry = map.get(md_path)?;
    Some(MarkdownHtml {
        markdown_path: entry.value().markdown_path.clone(),
        html_path: entry.value().html_path.clone(),
        cache_generated_time: entry.value().cache_generated_time,
        hash_code: entry.value().hash_code.clone(),
    })
}

// 打印
// pub fn print_cached() {
//     global_map().iter().for_each(|entity| {
//         println!(
//             "key:{}, value:{}",
//             entity.key(),
//             entity.value().html_path.display()
//         );
//     });
// }
